﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using ComputerEngine;
using System.Reflection;
using System.Diagnostics;

namespace EngineAdmin
{
    /// <summary>
    /// The main engine administrator facade object
    /// </summary>
    public class EngineAdministrator
    {
        private const string _sOpeningPath = "AppData\\Opening";
        private const string _sEGTBPath = "AppData\\EndGame";

        /// <summary>
        /// Map of engine's progress computing facade
        /// </summary>
        private Dictionary<Engine, EngineFacadeBase> _mapEngineProgress;

        public EngineAdministrator()
        {
            _mapEngineProgress = new Dictionary<Engine, EngineFacadeBase>();
        }

        public IEngineProgress LookUpProgress(Engine engine)
        {
            return _mapEngineProgress[engine] as IEngineProgress;
        }

        /// <summary>
        /// The main API method for creating engine
        /// </summary>
        public Engine CreateEngine(EngineConfig config)
        {
            // TO-DO: CheckersBoard engines
            if (config.EngineType == eEngineType.Internal)
                return CreateInternalEngine(config);
            else
                throw new NotImplementedException();
        }

        /// <summary>
        /// Closes the engine - terminates the threads
        /// </summary>
        public void CloseEngine(Engine engine)
        {
            // remove from the hash map
            _mapEngineProgress.Remove(engine);

            // close the engine
            engine.CloseEngine();
        }

        /// <summary>
        /// Creates the internal engine
        /// </summary>
        private Engine CreateInternalEngine(EngineConfig config)
        {
            // create engine
            Engine engine = new Engine(config);
            engine.InternalEngine = new ComputerEngine.Engine();
            EngineFacadeBase progress = new InternalEngineFacade(engine);

            // Opening database supported only for Czech Checkers
            // Think of better storage of opening paths
            if (config.CheckersType == eCheckersType.CzechCheckers)
            {
                // load opening database
                string sAppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                string sFullPath = Path.Combine(sAppPath, _sOpeningPath);
                bool result = engine.InternalEngine.LoadOpeningDatabase(sFullPath);
                Debug.Assert(result);

                // load EGTB database
                sFullPath = Path.Combine(sAppPath, _sEGTBPath);
                engine.InternalEngine.PreloadEndgameDatabase(sFullPath, 128);
            }

            // record the map
            _mapEngineProgress[engine] = progress;
            
            return engine;
        }

        /// <summary>
        /// The main API method for computing the move
        /// </summary>
        public IEngineProgress ComputeMove(Engine engine, GameStateConfig gameState)
        {
            // lookup engine progress facade
            EngineFacadeBase facade = null;
            if (_mapEngineProgress.TryGetValue(engine, out facade) == false)
            {
                throw new ApplicationException("Engine Facade not found");
            }

            // start computing move
            facade.ComputeMove(gameState);
                      
            return facade as IEngineProgress;
        }

        public int GetOpeningMoveCount(Engine engine)
        {
            return engine.InternalEngine.GetOpeningCount();
        }

        public List<BoardPos[]> GetOpeningByIndex(Engine engine, int index, GameStateConfig gameState)
        {
            // lookup engine progress facade
            EngineFacadeBase facade = null;
            if (_mapEngineProgress.TryGetValue(engine, out facade) == false)
            {
                throw new ApplicationException("Engine Facade not found");
            }

            return facade.GetOpeningByIndex(index, gameState);
        }

        /// <summary>
        /// Singleton pattern
        /// </summary>
        private static EngineAdministrator _instance = null;

        public static EngineAdministrator Instance()
        {
            // Remark: do not expect multithreaded support, skipping double-check control
            if (_instance == null)
                _instance = new EngineAdministrator();
            return _instance;
        }
    }
}
